package com.hmdp.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONUtil;
import com.hmdp.dto.Result;
import com.hmdp.entity.ShopType;
import com.hmdp.mapper.ShopTypeMapper;
import com.hmdp.service.IShopTypeService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author 虎哥
 * @since 2021-12-22
 */
@Service
public class ShopTypeServiceImpl extends ServiceImpl<ShopTypeMapper, ShopType> implements IShopTypeService {

    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    public static final String CACHE_SHOP_TYPE_KEY = "cache:shopType:";
    // 缓存过期时间（24小时，可根据业务调整）
    private static final Long CACHE_SHOP_TYPE_TTL = 24L;

    @Override
    public Result queryTypeList() {
        String key = CACHE_SHOP_TYPE_KEY;
        List<ShopType> shopTypes = null;

        try {
            // 1. 从Redis查询商铺类型缓存
            List<String> shopTypeJsonList = stringRedisTemplate.opsForList().range(key, 0, -1);
            // 2. 缓存存在：转换为对象并返回
            if (CollectionUtil.isNotEmpty(shopTypeJsonList)) {
                // 修复：遍历每个JSON字符串，单独转换为ShopType（而非整个列表toString）
                shopTypes = shopTypeJsonList.stream()
                        .map(json -> JSONUtil.toBean(json, ShopType.class))
                        .collect(Collectors.toList());
                // 移除多余排序：缓存数据与数据库一致，本身有序
                return Result.ok(shopTypes);
            }
        } catch (Exception e) {
            // Redis操作失败：打印日志，继续查询数据库（降级处理）
            log.error("Redis query shop type error", e);
            log.debug("👎👎");
        }

        // 3. 缓存不存在：查询数据库
        List<ShopType> dbShopTypes = query().orderByAsc("sort").list();
        // 4. 数据库无数据：返回错误
        if (CollectionUtil.isEmpty(dbShopTypes)) {
            return Result.fail("商铺类型不存在...");
        }

        // 5. 数据库有数据：写入Redis缓存
        try {
            // 转换为JSON字符串列表
            List<String> dbShopTypeJsonList = dbShopTypes.stream()
                    .map(shopType -> JSONUtil.toJsonStr(shopType))
                    .collect(Collectors.toList());
            // 写入Redis，并设置过期时间（解决数据一致性问题）
            stringRedisTemplate.opsForList().rightPushAll(key, dbShopTypeJsonList);
            stringRedisTemplate.expire(key, CACHE_SHOP_TYPE_TTL, TimeUnit.HOURS);
        } catch (Exception e) {
            // Redis写入失败：打印日志，不影响主流程（缓存降级）
            log.error("Redis write shop type error", e);
        }

        // 6. 返回数据库查询结果
        return Result.ok(dbShopTypes);
    }
}